package com.example.bbs.ui.activity;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import com.alibaba.fastjson.JSON;
import com.blankj.utilcode.util.LogUtils;
import com.example.bbs.R;
import com.example.bbs.base.App;
import com.example.bbs.base.Data;
import com.example.bbs.bean.MediaData;
import com.example.bbs.bean.Post;
import com.example.bbs.config.HttpConstant;
import com.example.bbs.ui.dialog.BottomListDialog;
import com.example.bbs.ui.dialog.CheckAlertDialog;
import com.example.bbs.ui.view.RichTextView;
import com.example.bbs.util.BaseUtil;
import com.example.bbs.util.HttpUtil;
import com.example.bbs.util.DisplayUtil;
import com.example.bbs.util.ImageUtil;
import com.example.bbs.util.LocationUtils;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class EditActivity extends AppCompatActivity implements View.OnClickListener{

    static class LoadMediaContract extends ActivityResultContract<Integer, MediaData> {

        static final int RECORDING_MASK = 0x0010;
        static final int TYPE_MASK = 0x000f;
        int requiredType; // Type in MediaData

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, Integer input) {
            requiredType = input & TYPE_MASK;
            String type = MediaData.fetchTypeName(input);
            if (type.isEmpty()) {
                Log.e(LOG_TAG, "insert media type error");
            }
            if (requiredType == MediaData.TYPE_AUDIO) {
                if ((input & RECORDING_MASK) != 0)
                    return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
                else {
                    return new Intent(Intent.ACTION_GET_CONTENT).setType(type);
                }
            }
            if (requiredType == MediaData.TYPE_VIDEO && ((input & RECORDING_MASK) != 0)) {
                return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            }
            return new Intent(Intent.ACTION_PICK).setType(type);
        }

        @Override
        public MediaData parseResult(int resultCode, @Nullable Intent intent) {
            if (intent == null || resultCode != Activity.RESULT_OK || intent.getData() == null)
                return null;
            return new MediaData(requiredType, intent.getData().toString(), "", "");
        }
    }

    static class TakePhotoContract extends ActivityResultContract<Integer, MediaData> {

        Uri uri = null;

        @SuppressLint("ObsoleteSdkInt")
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull Integer ignored) {
            uri = ImageUtil.saveBitmapToCache(null);
            return new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri);
        }

        @Override
        public final MediaData parseResult(int resultCode, @Nullable Intent intent) {
            if (intent == null || resultCode != Activity.RESULT_OK)
                return null;
            return new MediaData(MediaData.TYPE_IMAGE, uri.toString(), "", "");
        }
    }

    static final String LOG_TAG = EditActivity.class.getSimpleName();
    public static final String INTENT_EXTRA_POST = "post"; // type: Post
    static final int ANIMATING_TIME = 150; // milliseconds
    static final int INITIALING_PAGE_WAITING_TIME = 200; // milliseconds

    Button mbDraftBox;
    Button mbRelease;
    EditText etTitle;
    RichTextView rtvContent;
    TextView tvPosition;
    ImageView ivInsert;
    ImageView ivEmoji;
    LinearLayout llInsert;
    ImageView sivPicture;
    ImageView sivCamera;
    ImageView sivVideo;
    ImageView sivMusic;
    ImageView sivVoice;
    ImageView sivPosition;

    Post mOriginalPost;
    InputMethodManager imm;
    CheckAlertDialog mAlertDialog;
    int mKeyboardHeight = 0;
    boolean mKeyboardActive = false;

    // registerForActivityResult() 方法要在 onStart() 之前调用
    ActivityResultLauncher<Integer> mLoadMediaLauncher = registerForActivityResult(
            new LoadMediaContract(), (mediaData) -> rtvContent.addMediaData(mediaData));
    ActivityResultLauncher<Integer> mTakePhotoLauncher = registerForActivityResult(
            new TakePhotoContract(), (mediaData) -> rtvContent.addMediaData(mediaData));

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(LOG_TAG, "onCreate");
        setContentView(R.layout.activity_edit);

        initView();
        initClickListener();
        imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);

        // 版权声明：本文为CSDN博主「假装你是大灰狼」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
        // 原文链接：https://blog.csdn.net/chennai1101/article/details/82970070
        getWindow().getDecorView().addOnLayoutChangeListener(
             (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                    // 刷新高度 & 判断软键盘是否开启
                    int keyboardHeight = DisplayUtil.getSoftKeyBoardHeight(EditActivity.this);
                    if (keyboardHeight > 0) { // 软键盘开启
                        mKeyboardActive = true;
                        if (mKeyboardHeight != keyboardHeight) {
                            mKeyboardHeight = keyboardHeight;
                            setHeight(llInsert, mKeyboardHeight);
                        }
                    } else {
                        mKeyboardActive = false;
                    }
                });
        // 初始化页面后自动弹出软键盘，立即获取软键盘高度
        rtvContent.postDelayed(() ->
                imm.showSoftInput(rtvContent.requestInnerFocus(), InputMethodManager.SHOW_FORCED),
                INITIALING_PAGE_WAITING_TIME);
    }

    private void initView() {
        mbDraftBox = findViewById(R.id.mb_draft_box);
        mbRelease = findViewById(R.id.mb_release);
        etTitle = findViewById(R.id.et_title);
        rtvContent = findViewById(R.id.rtv_content);
        tvPosition = findViewById(R.id.tv_position_edit);
        ivEmoji = findViewById(R.id.iv_emoji);
        ivInsert = findViewById(R.id.iv_insert);
        llInsert = findViewById(R.id.ll_insert);
        llInsert.setVisibility(View.GONE);
        sivPicture = findViewById(R.id.siv_picture);
        sivCamera = findViewById(R.id.siv_camera);
        sivVideo = findViewById(R.id.siv_video);
        sivMusic = findViewById(R.id.siv_music);
        sivVoice = findViewById(R.id.siv_voice);
        sivPosition = findViewById(R.id.siv_position);

        Intent intent = getIntent();
        if (intent != null && intent.hasExtra(INTENT_EXTRA_POST)) {
            mOriginalPost = intent.getParcelableExtra(INTENT_EXTRA_POST);
            etTitle.setText(mOriginalPost.getTitle());
            rtvContent.init(mOriginalPost.getContent(), true);
        } else {
            mOriginalPost = null;
            rtvContent.init("", true);
        }
    }

    private void initClickListener() {
        mbDraftBox.setOnClickListener(this);
        mbRelease.setOnClickListener(this);
        etTitle.setOnClickListener(this);
        rtvContent.setMyOnClickListener(this); // 使用 setOnClickListener 时，内部的点击响应会被覆盖
        ivInsert.setOnClickListener(this);
        ivEmoji.setOnClickListener(this);
        sivPicture.setOnClickListener(this);
        sivCamera.setOnClickListener(this);
        sivVideo.setOnClickListener(this);
        sivMusic.setOnClickListener(this);
        sivVoice.setOnClickListener(this);
        sivPosition.setOnClickListener(this);
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(LOG_TAG, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(LOG_TAG, "onPause");

        rtvContent.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(LOG_TAG, "onDestroy");

        rtvContent.onDestroy();
    }

    @Override
    protected void onNewIntent(Intent intent) {

        super.onNewIntent(intent);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.d(LOG_TAG, "onOptionsItemSelected, MenuItem: " + item.getItemId());
        if (item.getItemId() == android.R.id.home) {
            hideSoftKeyBoard();
            if (checkDataChanged()) {
                showSavingDialog();
            } else {
                this.finish();
            }
            // rtnValue = true, 阻拦默认 ActionBar 的返回（这会重新创建一个 Activity）。
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        if (ivInsert.isSelected()) {
            handleBackPressedThenHidePanel(ivInsert, llInsert);
            return;
        }
        if (checkDataChanged()) {
            showSavingDialog();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public void onClick(View v) {

        int id = v.getId();

        if (id == R.id.mb_draft_box) {
            Intent intent = new Intent(this, DraftBoxActivity.class);
            startActivity(intent);

        } else if (id == R.id.mb_release) {
            hideSoftKeyBoard();
            uploadPost(true, this::finish);

        } else if (id == R.id.et_title || v instanceof EditText) { // 考虑 RichTextView 中的  EditText
            if (ivInsert.isSelected())
                handleEditTextFocusedThenHidePanel(ivInsert, llInsert);

        } else if (id == R.id.iv_insert) {
            if (etTitle.hasFocus())
                return;
            handleButtonClickedThenShiftLayout(ivInsert, llInsert);

        } else if (id == R.id.iv_emoji) {
            BaseUtil.showToastButtonInvalid();
            // TODO(Low): complete ivEmoji 的 OnClick 响应

        } else if (id == R.id.siv_picture) {
            mLoadMediaLauncher.launch(MediaData.TYPE_IMAGE);

        } else if (id == R.id.siv_camera) {
            mTakePhotoLauncher.launch(0);

        } else if (id == R.id.siv_video){
            new BottomListDialog.Builder(this)
                    .setItems(R.array.load_video_options, (dialog, pos) -> {
                        if (pos == 0) {
                            mLoadMediaLauncher.launch(MediaData.TYPE_VIDEO);
                        } else {
                            mLoadMediaLauncher.launch(MediaData.TYPE_VIDEO | LoadMediaContract.RECORDING_MASK);
                        }
                        dialog.cancel();
                    })
                    .setCancelable(true)
                    .show();

        } else if (id == R.id.siv_music) {
            mLoadMediaLauncher.launch(MediaData.TYPE_AUDIO);

        } else if (id == R.id.siv_voice) {
            // TODO(Low): 设计自定义的录音功能
            mLoadMediaLauncher.launch(MediaData.TYPE_AUDIO | LoadMediaContract.RECORDING_MASK);

        } else if (id == R.id.siv_position){
            initLocation();
        }
    }

    // TODO(Mid): 这里有光标被隐藏的问题
    // TODO(Low): 加入 Emoji，考虑不同面板之间的相互作用
    private void handleButtonClickedThenShiftLayout(View button, ViewGroup panel, ViewGroup... otherPanels) {

        // TODO(Mid): 有时插入的面板显示不出来
        Log.d(LOG_TAG, "state: " + !button.isSelected() + ", mKeyboardActive: " + mKeyboardActive + ", height: " + mKeyboardHeight);

        // 版权声明：本文为CSDN博主「forward123_」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
        // 原文链接：https://blog.csdn.net/u012964944/article/details/52120726
        button.setSelected(!button.isSelected());
        if (button.isSelected()) { // 打开插入的内容
            if (mKeyboardActive) { // 输入法打开: 锁住画面关闭输入法
                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
                hideSoftKeyBoard();
                panel.setVisibility(View.VISIBLE);
            }
            else { // 输入法关闭
                setHeight(panel, DisplayUtil.ZERO_HEIGHT);
                panel.setVisibility(View.VISIBLE);
                createChangingHeightAnimator(panel, DisplayUtil.ZERO_HEIGHT, mKeyboardHeight, ANIMATING_TIME,
                        () -> getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)).start();
            }
        }
        else { // 关闭插入的页面: 在锁住画面的情况下打开输入法，然后解锁，擦除插入的内容。
            View view = rtvContent.requestInnerFocus();
            imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
            view.postDelayed(() -> {
                panel.setVisibility(View.GONE);
                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
                getCurrentFocus().requestFocus();
            }, DisplayUtil.REFRESHING_PAGE_WAITING_TIME);
        }
    }

    private void handleBackPressedThenHidePanel(View button, ViewGroup panel) {
        button.setSelected(false);
        createChangingHeightAnimator(panel, panel.getHeight(), DisplayUtil.ZERO_HEIGHT
                , ANIMATING_TIME, () -> {
            panel.setVisibility(View.GONE);
            setHeight(panel, DisplayUtil.ZERO_HEIGHT);
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        }).start();
    }

    private void handleEditTextFocusedThenHidePanel(View button, ViewGroup panel) {
        button.setSelected(false);
        rtvContent.postDelayed(() -> {
            panel.setVisibility(View.GONE);
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        }, DisplayUtil.REFRESHING_PAGE_WAITING_TIME);
    }

    @SuppressWarnings("SameParameterValue")
    private ValueAnimator createChangingHeightAnimator(final View view, int start, int end, int time,
                                                       Runnable callback) {
        ValueAnimator animator = ValueAnimator.ofInt(start, end).setDuration(time);
        animator.addUpdateListener(
                animation -> setHeight(view, (int) animation.getAnimatedValue()));
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                callback.run();
            }
        });
        return animator;
    }

    private void setHeight(View view, int height) {
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        layoutParams.height = height;
        view.setLayoutParams(layoutParams);
    }

    private void hideSoftKeyBoard() {
        View view = getCurrentFocus();
        if (view instanceof EditText)
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

    private boolean checkDataChanged() {
        if (mOriginalPost == null)
            return !etTitle.getText().toString().isEmpty() || !rtvContent.isEmpty();
        return !mOriginalPost.getTitle().equals(etTitle.getText().toString()) ||
                !mOriginalPost.getContent().equals(rtvContent.getContent());
    }

    private void showSavingDialog() {
        if (mAlertDialog == null) {
            mAlertDialog = new CheckAlertDialog.Builder(this)
                    .setTitle(R.string.default_dialog_title)
                    .setMessage(R.string.dialog_content_save)
                    .setCancelable(true)
                    .setPositiveButton(R.string.dialog_button_save, (dialog, which) -> uploadPost(false, () -> {
                        dialog.cancel();
                        EditActivity.this.finish();
                    }))
                    .setNegativeButton(R.string.dialog_button_not_save, (dialog, which) -> {
                        dialog.cancel();
                        EditActivity.this.finish();
                    })
                    .show();
        } else {
            mAlertDialog.show();
        }
    }

    private void uploadPost(boolean published, Runnable callback) {
        Log.d(LOG_TAG, "upload post here");

        if (Data.myself == null) {
            Log.d(LOG_TAG, "uploading canceled, please login");
            runOnUiThread(() -> BaseUtil.showToast(R.string.toast_please_login)); // 检查是否登录
            return;
        }
        if (rtvContent.getStyle() != Post.STYLE_TEXT_ONLY) {
            BaseUtil.showToast(R.string.toast_uploading);
        }
        mbDraftBox.setEnabled(false);
        mbRelease.setEnabled(false);
        Runnable callbackWithAddition = () -> {
            callback.run();
            mbDraftBox.setEnabled(true);
            mbRelease.setEnabled(true);
        };
        rtvContent.checkAndUpload((bResult) -> { // 先上传图片，再上传内容
            if (!bResult) {
                // 上传图片失败，直接返回
                runOnUiThread(() -> BaseUtil.showToast(R.string.toast_uploading_failure));
                callbackWithAddition.run();
                return;
            }
            Log.d(LOG_TAG, "upload content: " + rtvContent.getContent());

            if (mOriginalPost == null) { // 如果是新的草稿，添加 Post
                Post newPost = new Post(etTitle.getText().toString(), rtvContent.getContent(),
                        rtvContent.generateAbstract(), Data.myself.getId(), rtvContent.getStyle(),
                        tvPosition.getText().toString());
                if (!published)
                    newPost.setType(Post.TYPE_DRAFT);
                HttpUtil.postAsync(HttpConstant.REQUEST_ADD_POST, JSON.toJSONString(newPost), (response) -> {
                    if (response != null  && response.getBoolean(HttpConstant.FIELD_REPLY))
                        Log.i(LOG_TAG, "add post success");
                    else
                        Log.w(LOG_TAG, "add post failure");
                    callbackWithAddition.run();
                });

            } else { // 如果是旧的草稿，更新 Post
                mOriginalPost.setTitle(etTitle.getText().toString());
                mOriginalPost.setContent(rtvContent.getContent());
                HttpUtil.postAsync(HttpConstant.REQUEST_UPDATE_POST, JSON.toJSONString(mOriginalPost),
                        (response) -> {
                    if (response != null  && response.getBoolean(HttpConstant.FIELD_REPLY))
                        Log.i(LOG_TAG, "update post success");
                    else
                        Log.w(LOG_TAG, "update post failure");
                    callbackWithAddition.run();
                });
            }
        });
    }

    /**
     * 加载位置
     */
    private void initLocation() {
        LocationUtils.getInstance(this).setAddressCallback(new LocationUtils.AddressCallback() {
            @Override
            public void onGetAddress(Address address) {
//                LogUtils.eTag("定位地址",countryName,adminArea,locality,subLocality,featureName);
                tvPosition.setText(address.getAddressLine(0));
            }

            @Override
            public void onGetLocation(double lat, double lng) {
                LogUtils.iTag("定位经纬度",lat,lng);
            }
        });
    }
}